package cn.yz.service.impl;

import cn.yz.dto.LoginDto;
import cn.yz.dto.UserDto;
import cn.yz.dto.UserPageDto;
import cn.yz.entity.User;
import cn.yz.exception.BusinessException;
import cn.yz.mapper.UserMapper;
import cn.yz.mapper.UserRoleMapper;
import cn.yz.result.ResultCode;
import cn.yz.service.UserService;
import cn.yz.util.JwtUtil;
import cn.yz.util.RedisUtil;
import cn.yz.util.SecurityUserUtil;
import cn.yz.vo.LoginVo;
import cn.yz.vo.PageVo;
import cn.yz.vo.UserVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户Service实现类
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Override
    public PageVo<UserVo> getUserPage(UserPageDto userPageDto) {
        // 构建查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(userPageDto.getUsername())) {
            queryWrapper.like(User::getUsername, userPageDto.getUsername());
        }
        if (StringUtils.hasText(userPageDto.getPhone())) {
            queryWrapper.like(User::getPhone, userPageDto.getPhone());
        }
        if (userPageDto.getStatus() != null) {
            queryWrapper.eq(User::getStatus, userPageDto.getStatus());
        }
        if (StringUtils.hasText(userPageDto.getEmail())) {
            queryWrapper.like(User::getEmail, userPageDto.getEmail());
        }
        
        // 排序
        if (StringUtils.hasText(userPageDto.getSortField())) {
            if ("asc".equalsIgnoreCase(userPageDto.getSortOrder())) {
                queryWrapper.orderByAsc(User::getCreateTime);
            } else {
                queryWrapper.orderByDesc(User::getCreateTime);
            }
        } else {
            queryWrapper.orderByDesc(User::getCreateTime);
        }

        // 分页查询
        Page<User> pageParam = new Page<>(userPageDto.getPage(), userPageDto.getSize());
        IPage<User> pageResult = this.page(pageParam, queryWrapper);

        // 转换为VO
        List<UserVo> userVos = pageResult.getRecords().stream()
                .map(this::convertToVo)
                .collect(Collectors.toList());

        return new PageVo<>(
                userVos,
                pageResult.getTotal(),
                pageResult.getCurrent(),
                pageResult.getSize()
        );
    }

    @Override
    public List<UserVo> getUserList(Integer page, Integer size, String username, String phone, Integer status) {
        // 构建查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(username)) {
            queryWrapper.like(User::getUsername, username);
        }
        if (StringUtils.hasText(phone)) {
            queryWrapper.like(User::getPhone, phone);
        }
        if (status != null) {
            queryWrapper.eq(User::getStatus, status);
        }
        queryWrapper.orderByDesc(User::getCreateTime);

        // 分页查询
        Page<User> pageParam = new Page<>(page, size);
        IPage<User> pageResult = this.page(pageParam, queryWrapper);

        // 转换为VO
        return pageResult.getRecords().stream().map(this::convertToVo).collect(Collectors.toList());
    }

    @Override
    public UserVo getUserById(String id) {
        User user = this.getById(id);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }
        return convertToVo(user);
    }

    @Override
    public void createUser(UserDto userDto) {
        // 检查用户名是否已存在
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, userDto.getUsername());
        if (this.count(queryWrapper) > 0) {
            throw new BusinessException(ResultCode.USER_ALREADY_EXISTS);
        }

        // 检查邮箱是否已存在
        if (StringUtils.hasText(userDto.getEmail())) {
            queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getEmail, userDto.getEmail());
            if (this.count(queryWrapper) > 0) {
                throw new BusinessException("邮箱已被注册");
            }
        }

        // 检查手机号是否已存在
        if (StringUtils.hasText(userDto.getPhone())) {
            queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getPhone, userDto.getPhone());
            if (this.count(queryWrapper) > 0) {
                throw new BusinessException("手机号已被注册");
            }
        }

        // 创建用户
        User user = new User();
        BeanUtils.copyProperties(userDto, user);
        user.setPassword(BCrypt.hashpw(userDto.getPassword(), BCrypt.gensalt()));
        user.setStatus(1); // 默认正常状态

        this.save(user);
    }

    @Override
    public void updateUser(String id, UserDto userDto) {
        User user = this.getById(id);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }

        // 检查用户名是否已被其他用户使用
        if (StringUtils.hasText(userDto.getUsername()) && !userDto.getUsername().equals(user.getUsername())) {
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getUsername, userDto.getUsername());
            queryWrapper.ne(User::getId, id);
            if (this.count(queryWrapper) > 0) {
                throw new BusinessException(ResultCode.USER_ALREADY_EXISTS);
            }
        }

        // 检查邮箱是否已被其他用户使用
        if (StringUtils.hasText(userDto.getEmail()) && !userDto.getEmail().equals(user.getEmail())) {
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getEmail, userDto.getEmail());
            queryWrapper.ne(User::getId, id);
            if (this.count(queryWrapper) > 0) {
                throw new BusinessException("邮箱已被其他用户使用");
            }
        }

        // 检查手机号是否已被其他用户使用
        if (StringUtils.hasText(userDto.getPhone()) && !userDto.getPhone().equals(user.getPhone())) {
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getPhone, userDto.getPhone());
            queryWrapper.ne(User::getId, id);
            if (this.count(queryWrapper) > 0) {
                throw new BusinessException("手机号已被其他用户使用");
            }
        }

        // 更新用户信息
        BeanUtils.copyProperties(userDto, user);
        if (StringUtils.hasText(userDto.getPassword())) {
            user.setPassword(BCrypt.hashpw(userDto.getPassword(), BCrypt.gensalt()));
        }

        this.updateById(user);
    }

    @Override
    public void deleteUser(String id) {
        User user = this.getById(id);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }

        // 这里可以添加业务逻辑，比如检查用户是否有关联数据
        // 暂时直接删除
        this.removeById(id);
    }

    @Override
    public void register(UserDto userDto) {
        // 检查用户名是否已存在
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, userDto.getUsername());
        if (this.count(queryWrapper) > 0) {
            throw new BusinessException(ResultCode.USER_ALREADY_EXISTS);
        }

        // 检查邮箱是否已存在
        if (userDto.getEmail() != null && !userDto.getEmail().isEmpty()) {
            queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getEmail, userDto.getEmail());
            if (this.count(queryWrapper) > 0) {
                throw new BusinessException("邮箱已被注册");
            }
        }

        // 检查手机号是否已存在
        if (userDto.getPhone() != null && !userDto.getPhone().isEmpty()) {
            queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getPhone, userDto.getPhone());
            if (this.count(queryWrapper) > 0) {
                throw new BusinessException("手机号已被注册");
            }
        }

        // 创建用户
        User user = new User();
        BeanUtils.copyProperties(userDto, user);
        user.setPassword(BCrypt.hashpw(userDto.getPassword(), BCrypt.gensalt()));
        user.setStatus(1); // 默认正常状态

        this.save(user);
    }

    @Override
    public LoginVo login(LoginDto loginDto) {
        // 根据用户名查询用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, loginDto.getUsername());
        User user = this.getOne(queryWrapper);

        if (user == null) {
            throw new BusinessException(ResultCode.USERNAME_OR_PASSWORD_ERROR);
        }

        // 检查用户状态
        if (user.getStatus() == 0) {
            throw new BusinessException(ResultCode.USER_ACCOUNT_DISABLED);
        }

        // 验证密码
        if (!BCrypt.checkpw(loginDto.getPassword(), user.getPassword())) {
            throw new BusinessException(ResultCode.USERNAME_OR_PASSWORD_ERROR);
        }

        // 更新最后登录信息
        user.setLastLoginTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        user.setLastLoginIp("127.0.0.1"); // 这里应该从请求中获取真实IP
        this.updateById(user);

        // 生成JWT令牌
        String accessToken = jwtUtil.generateToken(user.getUsername(), user.getId());
        String refreshToken = jwtUtil.generateToken(user.getUsername(), user.getId());

        // 将令牌存储到Redis
        redisUtil.set("token:" + user.getId(), accessToken, 86400); // 24小时过期
        redisUtil.set("refresh_token:" + user.getId(), refreshToken, 604800); // 7天过期

        // 构建登录响应
        LoginVo loginVo = new LoginVo();
        loginVo.setAccessToken(accessToken);
        loginVo.setRefreshToken(refreshToken);
        loginVo.setExpiresIn(86400L);

        // 构建用户信息
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        userVo.setGenderName(getGenderName(user.getGender()));
        userVo.setStatusName(getStatusName(user.getStatus()));
        userVo.setRoleIdList(userRoleMapper.selectUserRoleIds(user.getId()));
        loginVo.setUserInfo(userVo);

        return loginVo;
    }

    @Override
    public void logout(String token) {
        try {
            String userId = jwtUtil.getUserIdFromToken(token);
            redisUtil.del("token:" + userId);
            redisUtil.del("refresh_token:" + userId);
        } catch (Exception e) {
            log.warn("登出时解析token失败: {}", e.getMessage());
        }
    }

    @Override
    public LoginVo refreshToken(String refreshToken) {
        try {
            String username = jwtUtil.getUsernameFromToken(refreshToken);
            String userId = jwtUtil.getUserIdFromToken(refreshToken);

            // 验证刷新令牌是否在Redis中
            String storedRefreshToken = (String) redisUtil.get("refresh_token:" + userId);
            if (storedRefreshToken == null || !storedRefreshToken.equals(refreshToken)) {
                throw new BusinessException(ResultCode.UNAUTHORIZED, "刷新令牌无效");
            }

            // 生成新的访问令牌
            String newAccessToken = jwtUtil.generateToken(username, userId);
            redisUtil.set("token:" + userId, newAccessToken, 86400);

            LoginVo loginVo = new LoginVo();
            loginVo.setAccessToken(newAccessToken);
            loginVo.setRefreshToken(refreshToken);
            loginVo.setExpiresIn(86400L);

            return loginVo;
        } catch (Exception e) {
            throw new BusinessException(ResultCode.UNAUTHORIZED, "刷新令牌失败");
        }
    }

    @Override
    public UserVo getCurrentUser() {
        // 这里应该从SecurityContext中获取当前用户信息
        // 暂时返回null，实际使用时需要实现
        return null;
    }

    @Override
    public void updateUserInfo(UserDto userDto) {
        // 这里应该从SecurityContext中获取当前用户ID
        // 暂时抛出异常，实际使用时需要实现
        throw new BusinessException("功能暂未实现");
    }

    @Override
    public void changePassword(String oldPassword, String newPassword) {
        // 这里应该从SecurityContext中获取当前用户信息
        // 暂时抛出异常，实际使用时需要实现
        throw new BusinessException("功能暂未实现");
    }

    @Override
    public void resetPassword(String userId, String newPassword) {
        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }
        user.setPassword(BCrypt.hashpw(newPassword, BCrypt.gensalt()));
        user.setUpdateBy(SecurityUserUtil.getCurrentUsername());
        this.updateById(user);
    }

    /**
     * 转换User实体为UserVo
     */
    private UserVo convertToVo(User user) {
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        userVo.setGenderName(getGenderName(user.getGender()));
        userVo.setStatusName(getStatusName(user.getStatus()));
        return userVo;
    }

    /**
     * 获取性别名称
     */
    private String getGenderName(Integer gender) {
        if (gender == null) return "未知";
        switch (gender) {
            case 1:
                return "男";
            case 2:
                return "女";
            default:
                return "未知";
        }
    }

    /**
     * 获取状态名称
     */
    private String getStatusName(Integer status) {
        if (status == null) return "未知";
        switch (status) {
            case 1:
                return "正常";
            case 0:
                return "禁用";
            default:
                return "未知";
        }
    }

    public static void main(String[] args) {
        String newRawPassword = "yangzhen";
        String hashpw = BCrypt.hashpw(newRawPassword, BCrypt.gensalt());
        System.out.printf("原密码: %s, 加密后密码: %s%n", newRawPassword, hashpw);
    }
} 